package team.hyznrj.studentsys.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.mongodb.BasicDBObject;
import com.mongodb.WriteResult;

import lombok.extern.log4j.Log4j;
import team.hyznrj.studentsys.dto.StudentMessageSearchDto;
import team.hyznrj.studentsys.entity.DataReport;
import team.hyznrj.studentsys.entity.MongoArregateData;
import team.hyznrj.studentsys.entity.StudentMsgMap;
import team.hyznrj.studentsys.enums.DataReportEnum;
import team.hyznrj.studentsys.exception.AuthenticationOnFlagException;
import team.hyznrj.studentsys.exception.DataBaseObjectNull;
import team.hyznrj.studentsys.exception.DataBaseOperationError;
import team.hyznrj.studentsys.exception.DataIllegalException;
import team.hyznrj.studentsys.exception.DataNullException;
import team.hyznrj.studentsys.service.StudentMessageService;
import team.hyznrj.studentsys.service.StudentMsgMapService;
import team.hyznrj.studentsys.utils.HighMongoUtil;
import team.hyznrj.studentsys.utils.ValueUtil;

@Service
@Log4j
public class StudentMessageServiceImpl implements StudentMessageService {
	@Autowired
	StudentMsgMapService mapService;
	@Autowired
	StaticDatabasesValueCache cache;
	@Autowired
	HighMongoUtil<BasicDBObject> utils;
	private final static int LEVEL = 2;
	@Value("${SplitChar}")
	private String SPLIT_CHAR;
	/**
	 * 访问的collection
	 */
	@Value("${StudentMessageServiceDB}")
	private String DB;
	/**
	 * MongDB主键关键字
	 */
	@Value("${StudentMessageServicePrimaryKey}")
	private String PRIMARY_KEY;

	/**
	 * MongDB类库
	 */
	@Value("${StudentMessageServiceClazz}")
	private String CLAZZ;
	/**
	 * MongoDB文档的特殊标志字段
	 */
	@Value("${StudentMessageServiceFlag}")
	private String FLAG;

	/**
	 * 传入的List为条件，并判断Map是否符合 必要性条件 传出带map的数值(只存储相关的数据，其他数据忽视)
	 * 
	 * @param list
	 * @param map
	 * @return
	 * @throws DataNullException
	 */
	public BasicDBObject commonJudgeBasicDBObject(List<StudentMsgMap> list, Map<String, String> map, boolean update)
			throws DataNullException {
		BasicDBObject data = new BasicDBObject();
		for (int i = 0; i < list.size(); i++) {
			StudentMsgMap obj = list.get(i);
			String key = obj.getId();
			if (map.containsKey(key)) {
				/**
				 * 获取到数据，将数据放到数据表
				 */
				Object value = map.get(key);
				if (StringUtils.isEmpty(value) && obj.getNecessary()) {
					/* 必须的项信息为空,错误 */
					throw new DataNullException(obj.getValue() + "(必填)不能为空");
				}
				data.put(key, value == null ? "" : value);
			} else {
				if (!update && obj.getNecessary()) {
					/**
					 * 必须的项信息为空,错误
					 */
					throw new DataNullException(obj.getValue() + "(必填)不能为空");
				}
			}
		}
		if (map.containsKey(FLAG)) {
			data.put(FLAG, map.get(FLAG));
		}
		data.put(PRIMARY_KEY, new ObjectId());
		if (update) {
			return new BasicDBObject("$set", data);
		}
		return data;
	}

	private Criteria setFlagPattern(final Criteria c, final String flag, final int level) {
		return c.and(FLAG).regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, level), -1));
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object addMsg(Map<String, String> message, String flag)
			throws DataNullException, DataBaseObjectNull, AuthenticationOnFlagException {
		/* 数据结果 */
		if (message == null) {
			throw new DataNullException("映射数据不能为空");
		}
		/**
		 * 将文档标志字段放入
		 */
		message.put(FLAG, ValueUtil.getFlag(flag, 3));
		/**
		 * 读映射表
		 */
		List<StudentMsgMap> list;
		list = (List<StudentMsgMap>) mapService.getAllMsg(flag).getData();
		BasicDBObject data = commonJudgeBasicDBObject(list, message, false);
		utils.save(data, DB);
		setResult(data);
		return data;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object addMsgMulity(List<Map<String, String>> message, String flag)
			throws DataNullException, DataBaseObjectNull, AuthenticationOnFlagException {
		if (message == null || message.size() == 0) {
			throw new DataNullException("映射数据不能为空");
		}
		List<BasicDBObject> lis = new ArrayList<>();
		/**
		 * 读映射表
		 */
		List<StudentMsgMap> list;
		list = (List<StudentMsgMap>) mapService.getAllMsg(flag).getData();
		String $flag = ValueUtil.getFlag(flag, 3);
		for (int j = 0; j < message.size(); j++) {
			Map<String, String> map = message.get(j);
			/**
			 * 将文档标志字段放入
			 */
			map.put(FLAG, $flag);
			BasicDBObject data = commonJudgeBasicDBObject(list, map, false);
			lis.add(data);
		}
		utils.saveList(lis, DB);
		for (BasicDBObject msg : lis) {
			setResult(msg);
		}
		return lis;
	}

	/**
	 * 批量删除
	 */
	@Override
	public int deleteMsg(Map<String, String> message, String flag)
			throws DataNullException, DataBaseOperationError, AuthenticationOnFlagException {
		boolean single = false;
		Object result = null;
		Set<String> keySet = null;
		/**
		 * 异常流检测
		 */
		if (StringUtils.isEmpty(flag)) {
			throw new AuthenticationOnFlagException();
		}
		if (message == null) {
			throw new DataNullException("数据不能为空");
		} else {
			keySet = message.keySet();
		}
		if (keySet == null || keySet.size() <= 0) {
			throw new DataNullException("键不能为空");
		}
		Query query = new Query();
		for (String key : keySet) {
			Object value = message.get(key);
			if (value == null) {
				throw new DataNullException("数据不能为空");
			}
			/**
			 * 如果存在主键，则进行单条操作
			 */
			if (key.equals(PRIMARY_KEY)) {
				value = new ObjectId(String.valueOf(value));
				single = true;
			}
			Criteria criteria = Criteria.where(key).is(value);
			setFlagPattern(criteria, flag, LEVEL);
			query.addCriteria(criteria);
		}
		if (single) {
			/**
			 * 单操作
			 */
			result = utils.deleteById(query, DB);
			if (result != null) {
				return 1;
			} else {
				throw new DataBaseOperationError("删除0个数据", DataReportEnum.DELETE_ERROR);
			}
		} else {
			/**
			 * 批量操作
			 */
			WriteResult delete = utils.delete(query, DB);
			result = delete;
			if (delete != null && delete.getN() > 0) {
				return delete.getN();
			} else {
				throw new DataBaseOperationError("删除0个数据", DataReportEnum.DELETE_ERROR);
			}
		}
	}

	@Override
	public WriteResult deleteMsg(List<String> idList, String flag)
			throws DataNullException, DataBaseOperationError, AuthenticationOnFlagException {
		/**
		 * 异常流检测
		 */
		if (StringUtils.isEmpty(flag)) {
			throw new AuthenticationOnFlagException();
		}
		if (idList == null || idList.size() == 0) {
			throw new DataNullException("数据不能为空");
		}
		Query query = new Query();
		List<ObjectId> keys = new ArrayList<>();
		for (int i = 0; i < idList.size(); i++) {
			keys.add(new ObjectId(idList.get(i)));
		}
		Criteria criteria = Criteria.where(PRIMARY_KEY).in(keys);
		setFlagPattern(criteria, flag, LEVEL);
		query.addCriteria(criteria);
		WriteResult delete = utils.delete(query, DB);
		if (delete != null && delete.getN() > 0) {
			return delete;
		} else {
			throw new DataBaseOperationError("删除0个数据", DataReportEnum.DELETE_ERROR);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public WriteResult updateMsg(Map<String, String> conditions, Map<String, String> newMessage, String flag)
			throws DataNullException, DataBaseOperationError, DataBaseObjectNull, AuthenticationOnFlagException {
		if (conditions == null || newMessage == null || newMessage.isEmpty()) {
			throw new DataNullException("数据不能为空");
		}
		Query query = new Query();
		/**
		 * 数据有效性检查
		 */
		List<StudentMsgMap> list = (List<StudentMsgMap>) mapService.getAllMsg(flag).getData();
		newMessage.put(FLAG, ValueUtil.getFlag(flag, LEVEL));
		BasicDBObject basicDBObject = commonJudgeBasicDBObject(list, newMessage, true);
		Update update = Update.fromDBObject(basicDBObject);
		if (conditions.containsKey(PRIMARY_KEY)) {
			/**
			 * 单一情况需要单更新
			 */
			Object object = conditions.get(PRIMARY_KEY);
			if (object == null) {
				throw new DataNullException("数据不能为空");
			}
			query.addCriteria(Criteria.where(String.valueOf(PRIMARY_KEY)).is(new ObjectId(String.valueOf(object)))
					.and(FLAG).regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, LEVEL), -1)));
			WriteResult result = utils.updateFirst(query, update, DB);
			if (result != null && result.getN() > 0) {
				return result;
			} else {
				throw new DataBaseOperationError("更新失败", DataReportEnum.UPDATE_ERROR);
			}
		} else {
			/**
			 * 如果不包含_id,则循环
			 */
			Set<String> keySet = conditions.keySet();
			for (String key : keySet) {
				Object object = conditions.get(key);
				System.out.println(key + " ->" + object);
				if (!StringUtils.isEmpty(object)) {
					query.addCriteria(Criteria.where(key).is(object));
				}
			}
			/* 批量更新 */
			WriteResult result = utils.updateMulity(query, update, DB);
			if (result != null && result.getN() > 0) {
				return result;
			} else {
				throw new DataBaseOperationError("更新失败", DataReportEnum.UPDATE_ERROR);
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public String updateMsgByKeyList(List<String> idList, Map<String, String> newMessage, String flag)
			throws DataNullException, DataBaseOperationError, DataBaseObjectNull, AuthenticationOnFlagException {
		/**
		 * 异常流
		 */
		if (idList == null || newMessage == null || newMessage.size() == 0) {
			throw new DataNullException("数据不能为空");
		}
		if (StringUtils.isEmpty(flag)) {
			throw new AuthenticationOnFlagException();
		}
		/**
		 * 核心操作
		 */
		List<StudentMsgMap> list = (List<StudentMsgMap>) mapService.getAllMsg(flag).getData();
		BasicDBObject basicDBObject = commonJudgeBasicDBObject(list, newMessage, true);
		Update update = Update.fromDBObject(basicDBObject);
		Query query = new Query();
		List<ObjectId> keys = new ArrayList<>();
		for (int i = 0; i < idList.size(); i++) {
			keys.add(new ObjectId(idList.get(i)));
		}
		Criteria criteria = Criteria.where(PRIMARY_KEY).in(keys).and(FLAG)
				.regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, LEVEL), -1));
		query.addCriteria(criteria);
		WriteResult result = utils.updateMulity(query, update, DB);
		if (result != null) {
			return "成功更新(" + result.getN() + "," + idList.size() + ")个数据";
		} else {
			throw new DataBaseOperationError("更新失败", DataReportEnum.UPDATE_ERROR);
		}
	}

	public void setResult(BasicDBObject result) {
		result.put(PRIMARY_KEY, result.getString(PRIMARY_KEY));
		result.remove(CLAZZ);
		result.remove(FLAG);
	}

	@Override
	public List<BasicDBObject> getMsg(Map<String, String> conditions, String flag, boolean direction)
			throws DataBaseOperationError, DataNullException, AuthenticationOnFlagException {
		DataReport dataReport = new DataReport();
		List<BasicDBObject> result = new ArrayList<>();
		if (conditions == null) {
			throw new DataNullException("数据不能为空");
		} else {
			conditions = new ValueUtil<String>().getMap(conditions, false);
			Query query = new Query();
			/**
			 * 左查询文档特殊标志位
			 */
			query.addCriteria(
					Criteria.where(FLAG).regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, LEVEL), -1)));
			/**
			 * 如果存在主键则单查询
			 */
			if (conditions.containsKey(PRIMARY_KEY)) {
				query.addCriteria(Criteria.where(PRIMARY_KEY).is(new ObjectId(conditions.get(PRIMARY_KEY))));
				// flag必须以 .*?#开头(同一院系)
				BasicDBObject tmp = utils.find(query, BasicDBObject.class, DB);
				// 防止解析ObjectId
				setResult(tmp);
				result.add(tmp);
			} else {
				Set<String> set = conditions.keySet();
				for (String key : set) {
					/**
					 * direction true时左查询 false时模糊查询
					 */
					if (direction) {
						query.addCriteria(
								Criteria.where(key).regex(ValueUtil.getRegexPattern(conditions.get(key).trim(), -1)));
					} else {
						query.addCriteria(
								Criteria.where(key).regex(ValueUtil.getRegexPattern(conditions.get(key).trim(), 2)));
					}
				}
				result = utils.findMulity(query, BasicDBObject.class, DB);
				for (int i = 0; i < result.size(); i++) {
					BasicDBObject tmp = result.get(i);
					// 防止解析ObjectId
					setResult(tmp);
				}
				dataReport.setData(result);
			}
		}
		return result;
	}

	public long getStudentsSnoCount(StudentMessageSearchDto dto) {
		return utils.count(getQueryByStudentMessageSearchDto(dto), BasicDBObject.class, DB);
	}

	@Override
	public List<BasicDBObject> getStudentsSno(StudentMessageSearchDto dto) {
		List<BasicDBObject> result = new ArrayList<>();
		if (dto == null || dto.getConditions() == null || dto.getConditions().isEmpty()
				|| StringUtils.isEmpty(dto.getFlag())) {
			// pass...
			throw new DataNullException("查询条件不能为空");
		} else {
			Query query = getQueryByStudentMessageSearchDto(dto);
			List<BasicDBObject> tmpList = utils.findMulity(query, BasicDBObject.class, DB);
			for (int i = 0; i < tmpList.size(); i++) {
				BasicDBObject tmp = tmpList.get(i);
				setResult(tmp);
				result.add(tmp);
			}
		}
		if(result.size()==0){
			throw new DataNullException("查询结果为空");
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	private Query getQueryByStudentMessageSearchDto(StudentMessageSearchDto dto) {
		Query query = new Query();
		String flag = dto.getFlag();
		/**
		 * 左查询文档特殊标志位
		 */
		query.addCriteria(Criteria.where(FLAG).regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, LEVEL), -1)));
		if (dto.isOpenPage() && dto.getPageIndex() != null && dto.getPageSize() != null) {
			query.skip((dto.getPageIndex() - 1) * dto.getPageSize()).limit(dto.getPageSize());
		}
		Map<String, String> conditions = dto.getConditions();
		/** 值->id映射 */
		Map<String, String> idMap = new HashMap<>();
		Set<String> set = conditions.keySet();
		List<StudentMsgMap> allMsg = null;
		try {
			allMsg = (List<StudentMsgMap>) mapService.getAllMsg(flag).getData();
			for (StudentMsgMap msgMap : allMsg) {
				idMap.put(msgMap.getValue(), msgMap.getId());
			}
		} catch (Exception e) {
			throw new DataIllegalException("登录状态异常");
		}
		/**
		 * 将Map中的条件加进去
		 */
		String val = null;
		for (String key : set) {
			int x=-1;
			if(dto.getModel()==-1){
				x=2;
			}else if(dto.getModel()<=2&&dto.getModel()>=0){
				x=dto.getModel();
			}else{
				throw new DataIllegalException("字符串查询匹配模式错误");
			}
			List<String> list = ValueUtil.splitKey(conditions.get(key), SPLIT_CHAR);
			// Criteria regex = Criteria.where(idMap.get(key)).in(list);
			List<Criteria> tmp = new ArrayList<>();
			for (int i = 0; i < list.size(); i++) {
				val = list.get(i);
				if (!StringUtils.isEmpty(val)) {
					if (idMap.containsKey(key) || idMap.containsValue(key)) {
						Criteria regex = null;
						/** 如果是作为key值存在，则从key里寻找id */
						if (idMap.containsKey(key)) {
							regex = Criteria.where(idMap.get(key)).regex(ValueUtil.getRegexPattern(val, x));
						} else {
							/** 如果是直接传入id,则用id查询 */
							regex = Criteria.where(key).regex(ValueUtil.getRegexPattern(val, x));
						}
						tmp.add(regex);
					}
				}
			}
			/**
			 * Size为1则不需要与操作
			 */
			if (tmp.size() == 1) {
				query.addCriteria(tmp.get(0));
			} else {
				query.addCriteria(new Criteria().orOperator(tmp.toArray(new Criteria[tmp.size()])));
			}
			tmp.clear();
		}
		return query;
	}

	@Override
	public List<String> getAggregateKeyWords(String keyWords, String flag) {
		Query query = new Query();
		/**
		 * 左查询文档特殊标志位
		 */
		query.addCriteria(Criteria.where(FLAG).regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, LEVEL), -1)));

		String key = null;
		Map<String, String> allMsgIdMap = mapService.getAllMsgIdMap(flag);
		if (allMsgIdMap.containsKey(keyWords)) {
			key = allMsgIdMap.get(keyWords);
		}
		if (allMsgIdMap.containsValue(keyWords)) {
			key = keyWords;
		}
		if (key != null) {
			MongoArregateData group = utils.group(key, query, BasicDBObject.class, DB);
			return group.getKeyWords();
		} else {
			return null;
		}

	}

	@Override
	public List<String> getPIDByKeywords(StudentMessageSearchDto dto) {
		List<BasicDBObject> studentsSno = this.getStudentsSno(dto);
		List<String> result = new ArrayList<>();
		for (int i = 0; i < studentsSno.size(); i++) {
			result.add(studentsSno.get(i).getString(PRIMARY_KEY));
		}
		return result;
	}

	@Override
	public List<BasicDBObject> getMsgByIds(List<String> ids, String flag) {
		List<BasicDBObject> result = null;
		if (ids == null || ids.size() == 0) {
			throw new DataNullException("数据不能为空");
		} else {
			Query query = new Query();
			/**
			 * 左查询文档特殊标志位
			 */
			query.addCriteria(
					Criteria.where(FLAG).regex(ValueUtil.getRegexPattern(ValueUtil.getFlag(flag, LEVEL), -1)));
			/**
			 * 如果存在主键则单查询
			 */
			List<StudentMsgMap> list = (List<StudentMsgMap>) mapService.getAllMsg(flag).getData();
			List<ObjectId> objs = new ArrayList<>();
			for (int i = 0; i < ids.size(); i++) {
				try {
					objs.add(new ObjectId(ids.get(i)));
				} catch (IllegalArgumentException e) {
					log.warn("getMsgByIds:" + "#" + ids.get(i) + "转化为ObjectId失败");
				}
			}
			query.addCriteria(Criteria.where(PRIMARY_KEY).in(objs));
			// flag必须以 .*?#开头(同一院系)
			result = utils.findMulity(query, BasicDBObject.class, DB);
			if (result != null) {
				for (int i = 0; i < result.size(); i++) {
					BasicDBObject tmp1 = result.get(i);
					// 防止解析ObjectId
					if (tmp1 != null) {
						setResult(tmp1);
					}
				}
			}
		}
		return result;
	}

	@Override
	public List<String> getSnoByIds(List<String> ids, String flag) {

		List<BasicDBObject> msgByIds = getMsgByIds(ids, flag);
		if (msgByIds == null || msgByIds.size() == 0) {
			return null;
		} else {
			List<String> result = new ArrayList<>();
			String str = mapService.getAllMsgIdMap(flag).get("学号");
			for (BasicDBObject b : msgByIds) {
				result.add(b.getString(str));
			}
			return result;
		}
	}
}
